package lbframework.classe;

import gnu.io.CommPortIdentifier;
import gnu.io.ParallelPort;
import gnu.io.ParallelPortEvent;
import gnu.io.ParallelPortEventListener;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;

public class SComm implements Runnable, SerialPortEventListener, ParallelPortEventListener {

    public static int PARITY_NONE = 0;
    public static int PARITY_ODD = 1;
    public static int PARITY_EVEN = 2;
    public static int PARITY_MARK = 3;
    public static int PARITY_SPACE = 4;
    private String porta;
    private int baudrate;
    private int timeout;
    private int databits;
    private int stopbits;
    private int parity;
    public String Dadoslidos = "";
    private CommPortIdentifier cp;
    private SerialPort serialPort;
    private ParallelPort parallelPort;
    private OutputStream outputStream;
    private InputStream inputStream;
    private Thread threadLeitura;
    private boolean leitura = false;
    private boolean escrita = false;

    public SComm(String i_porta, int i_baudrate, int i_timeout, int i_databits, int i_stopbits, int i_parity) {
        this.porta = i_porta;
        this.baudrate = i_baudrate;
        this.timeout = i_timeout;
        this.databits = i_databits;
        this.stopbits = i_stopbits;
        this.parity = i_parity;
    }

    public void setEscrita(boolean value) {
        escrita = value;
    }

    public void setLeitura(boolean value) {
        leitura = value;
    }

    public void portOpen() throws Exception {
        cp = CommPortIdentifier.getPortIdentifier(porta);

        if (cp == null) {
            throw new LBException("A porta " + porta + " não existe!");
        }

        try {
            if (cp.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                serialPort = (SerialPort) cp.open(porta, timeout);

            } else if (cp.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
                parallelPort = (ParallelPort) cp.open(porta, 100);
            }
        } catch (PortInUseException ex) {
            throw new LBException("A porta " + porta + " já está sendo usada!");
        }

        if (cp.getPortType() == CommPortIdentifier.PORT_SERIAL) {
            serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);        
        }
    }

    public void sendData(String msg) throws Exception {
        if (escrita == true) {
            if (cp.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                outputStream = serialPort.getOutputStream();

            } else if (cp.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
                outputStream = parallelPort.getOutputStream();
            }

            outputStream.write(msg.getBytes());            
            Thread.sleep(100);

            outputStream.flush();
        }
    }

    public void getData() throws Exception {
        if (leitura == true) {
            if (serialPort != null) {
                inputStream = serialPort.getInputStream();

                serialPort.addEventListener(this);
                serialPort.notifyOnDataAvailable(true);

                threadLeitura = new Thread(this);
                threadLeitura.start();

            } else if (parallelPort != null) {
                inputStream = parallelPort.getInputStream();

                parallelPort.addEventListener(this);
                parallelPort.notifyOnBuffer(true);

                threadLeitura = new Thread(this);
                threadLeitura.start();
            }
        }
    }

    public static Vector<String> getPortas(boolean i_serial, boolean i_paralela) throws Exception {
        Enumeration ports = CommPortIdentifier.getPortIdentifiers();
        CommPortIdentifier cp;

        Vector vPorta = new Vector();

        while (ports.hasMoreElements()) {
            cp = (CommPortIdentifier) ports.nextElement();

            if (i_paralela && !i_serial) {
                if (cp.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
                    vPorta.add(cp.getName());
                }

            } else if (i_serial && !i_paralela) {
                if (cp.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                    vPorta.add(cp.getName());
                }
            } else {
                vPorta.add(cp.getName());
            }
        }

        return vPorta;
    }

    public void run() {
        try {
            Thread.sleep(5000);

        } catch (Exception ex) {
            Util.exibirMensagemErro(ex, "Atenção");
        }
    }

    //gerenciador de eventos de leitura na serial
    public void serialEvent(SerialPortEvent ev) {
        try {
            switch (ev.getEventType()) {
                case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                    break;
                case SerialPortEvent.DATA_AVAILABLE:
                    byte[] bufferLeitura = new byte[20];

                    Thread.sleep(50);

                    while (inputStream.available() > 0) {
                        inputStream.read(bufferLeitura);
                    }

                    Dadoslidos += new String(bufferLeitura).trim();
                    onComm(Dadoslidos);
                    Dadoslidos = "";

                    break;
            }
        } catch (Exception ex) {
            Util.exibirMensagemErro(ex, "Atenção");
        }
    }

    public void portClose() throws Exception {
        if (cp.getPortType() == CommPortIdentifier.PORT_SERIAL) {
            serialPort.close();

        } else if (cp.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
            parallelPort.close();
        }
    }

    public String getPorta() {
        return porta;
    }

    public int getBaudrate() {
        return baudrate;
    }

    public void onComm(String i_dataArrival) {
    }

    public void parallelEvent(ParallelPortEvent ppe) {
        try {
            switch (ppe.getEventType()) {
                case ParallelPortEvent.PAR_EV_BUFFER:
                    byte[] bufferLeitura = new byte[20];

                    Thread.sleep(50);

                    while (inputStream.available() > 0) {
                        inputStream.read(bufferLeitura);
                    }

                    Dadoslidos += new String(bufferLeitura).trim();
                    onComm(Dadoslidos);
                    Dadoslidos = "";

                    break;
            }
        } catch (Exception ex) {
            Util.exibirMensagemErro(ex, "Atenção");
        }
    }
}
